pip install scipy
pip install imutils
OpenCV邊緣偵測
1.1 影像前處理
def preprocessing(image):
# 灰階
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
show_img('gray', gray)
# 高斯濾波
gaussian = cv2.GaussianBlur(gray, (9, 9), 0)
show_img("gaussian", gaussian)
# 開運算去除白色噪點
kernel = np.ones((9, 9), np.uint8)
open = cv2.morphologyEx(gaussian, cv2.MORPH_OPEN,
kernel, iterations=3)
show_img("open", open)
return open
1.2 Canny影像邊緣檢測
def edge_detect(image):
# 以canny邊緣檢測算法獲取目標(50~100為閾值)
edged = cv2.Canny(image, 50, 100) #低於50刪除 高於100留下
show_img("edged", edged)
# 在邊緣圖像中尋找物體輪廓
contours1, hierarchy = cv2.findContours(edged.copy(),
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
# 物體輪廓由左到右進行排序
(contours2, _) = contours.sort_contours(contours1)
# 若輪廓面積小於100,視為噪音濾除
contours2 = [i for i in contours2 if cv2.contourArea(i) > 100]
# 初始化pixelsPerMetric
pixelsPerMetric = None
return contours2, pixelsPerMetric
1.3 計算輪廓長度高度,並畫出外切線框
# 計算物體像素尺寸,並轉換為實際尺寸
def measure(image, contours2, pixelsPerMetric):
origin = image.copy()
for i in contours2:
# 計算出物品輪廓之外切線框
box = cv2.minAreaRect(i)
box = cv2.cv.BoxPoints(box) if imutils.is_cv2() \
else cv2.boxPoints(box)
box = np.array(box, dtype="int")
# 左上角座標開始順時針排序,並畫出外切線框
box = perspective.order_points(box)
cv2.drawContours(origin, [box.astype("int")], -1, (0, 255, 0), 2)
# 畫書外切線框端點
for (x, y) in box:
cv2.circle(origin, (int(x), int(y)), 5, (0, 0, 255), -1)
#算出左上和右上端點的中心點、左下和右下端點的中心點
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
# 算出左上和左下端點的中心點、右上和右下端點的中心點
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
# 計算兩個中心點距離(dA:寬、dB:長)
dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
# 像素值與最左邊物品實際長度比值
if pixelsPerMetric is None:
pixelsPerMetric = dB / image_width
# 計算目標的實際大小
dimA = dA / pixelsPerMetric
dimB = dB / pixelsPerMetric
# 在圖片中標註物體尺寸
cv2.putText(origin, "{:.1f}cm".format(dimB),
(int(tltrX - 15), int(tltrY - 10)),
cv2.FONT_HERSHEY_SIMPLEX,
0.65, (255, 255, 255), 2)
cv2.putText(origin, "{:.1f}cm".format(dimA),
(int(trbrX - 10), int(trbrY)),
cv2.FONT_HERSHEY_SIMPLEX,
0.65, (255, 255, 255), 2)
show_img("Image", origin)
return origin
1.4 完整程式碼
from scipy.spatial import distance as dist
from imutils import perspective
from imutils import contours
import numpy as np
import imutils
import cv2
# 讀取中文路徑圖檔(圖片讀取為BGR)
def cv_imread(image_path):
image = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), -1)
image = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR)
return image
# 顯示圖檔
def show_img(name, image):
cv2.imshow(name, image)
cv2.waitKey(0)
# 圖片預處理
def preprocessing(image):
# 灰階
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
show_img('gray', gray)
# 高斯濾波
gaussian = cv2.GaussianBlur(gray, (9, 9), 0)
show_img("gaussian", gaussian)
# 開運算去除白色噪點
kernel = np.ones((9, 9), np.uint8)
open = cv2.morphologyEx(gaussian, cv2.MORPH_OPEN,
kernel, iterations=3)
show_img("open", open)
return open
# 計算物體中間點
def midpoint(point1, point2):
point = ((point1[0]+point2[0])/2, (point1[1]+point2[1])/2)
return point
def edge_detect(image):
# 以canny邊緣檢測算法獲取目標(50~100為閾值)
edged = cv2.Canny(image, 50, 100) #低於50刪除 高於100留下
show_img("edged", edged)
# 在邊緣圖像中尋找物體輪廓
contours1, hierarchy = cv2.findContours(edged.copy(),
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
# 物體輪廓由左到右進行排序
(contours2, _) = contours.sort_contours(contours1)
# 若輪廓面積小於100,視為噪音濾除
contours2 = [i for i in contours2 if cv2.contourArea(i) > 100]
# 初始化 pixels per metric
pixelsPerMetric = None
return contours2, pixelsPerMetric
# 計算物體像素尺寸,並轉換為實際尺寸
def measure(image, contours2, pixelsPerMetric):
origin = image.copy()
for i in contours2:
# 計算出物品輪廓之外切線框
box = cv2.minAreaRect(i)
box = cv2.cv.BoxPoints(box) if imutils.is_cv2() \
else cv2.boxPoints(box)
box = np.array(box, dtype="int")
# 左上角座標開始順時針排序,並畫出外切線框
box = perspective.order_points(box)
cv2.drawContours(origin, [box.astype("int")], -1, (0, 255, 0), 2)
# 畫書外切線框端點
for (x, y) in box:
cv2.circle(origin, (int(x), int(y)), 5, (0, 0, 255), -1)
# 算出左上和右上端點的中心點、左下和右下端點的中心點
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
# 算出左上和左下端點的中心點、右上和右下端點的中心點
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
# 計算兩個中心點距離(dA:寬、dB:長)
dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
# 像素值與最左邊物品實際長度比值
if pixelsPerMetric is None:
pixelsPerMetric = dB / image_width
# 計算目標的實際大小
dimA = dA / pixelsPerMetric
dimB = dB / pixelsPerMetric
# 在圖片中標註物體尺寸
cv2.putText(origin, "{:.1f}cm".format(dimB),
(int(tltrX - 15), int(tltrY - 10)),
cv2.FONT_HERSHEY_SIMPLEX,
0.65, (255, 255, 255), 2)
cv2.putText(origin, "{:.1f}cm".format(dimA),
(int(trbrX - 10), int(trbrY)),
cv2.FONT_HERSHEY_SIMPLEX,
0.65, (255, 255, 255), 2)
show_img("Image", origin)
return origin
if __name__ == "__main__":
image_path = './edge.jpg'
image_width = 10.8
image = cv_imread(image_path)
show_img("image", image)
gray = preprocessing(image)
contours2, pixelsPerMetric = edge_detect(gray)
measure(image, contours2, pixelsPerMetric)
1.5 執行結果
讀取edge.jpg原圖
將圖片轉換成灰階
高斯模糊保留圖像主要輪廓,並降低躁點影響。
開運算去除白色噪點(如:滑鼠上白色英文單字)
以Canny邊緣檢測算法獲取待量測物體
計算輪廓長度高度,並畫出外切線框
讓我們繼續看下去...